/*

Copyright (C) 2000 - 2008 Christian Kreibich <christian@whoop.org>.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

// #include <unistd.h>
// #include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#ifdef LINUX
#define __FAVOR_BSD
#endif

#include <gtk/gtk.h>
#include <nd.h>
// #include <nd_clipboard.h>
#include <nd_gui.h>
#include <nd_macros.h>
// #include <nd_packet.h>
// #include <nd_prefs.h>
// #include <nd_protocol.h>
// #include <nd_protocol_inst.h>
// #include <nd_tp.h>
#include <nd_trace_registry.h>
// #include <callbacks.h>
// #include <interface.h>
#include <support.h>

#define STATUSBAR_TIMEOUT            5
#define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (((GtkObject*) (_widget_))->klass)
#define PBAR_ACTIVITY_BLOCKS         10

#define ND_GTK_BUILDER_FILE "netdude.xml"


/* global list of gtk objects */
GtkBuilder				 *nd_builder = NULL;
GtkWindow				 *nd_toplevel_window = NULL;
GtkUIManager			 *nd_ui_manager = NULL;


static GtkProgressBar   *pbar;
static int               pbar_total;
static int               pbar_current;
static gboolean          pbar_activity_mode;
static int               pbar_timeout_set;
static gfloat            pbar_old_ratio = -1.0;

static GdkPixmap        *incomplete_pmap;
static GdkBitmap        *incomplete_mask;

static guint             timestamp_id;
static int               timestamp_set = FALSE;

static GdkColor          bg[5];
static GdkColor          red[5];
static GdkColor          yellow[5];

static GtkTooltips*      tt;

static GList            *monowidth_widgets = NULL;

static GtkWidget        *iterator_menu;

static gchar            *list_titles[2] = { N_("Tcpdump log"), N_("State") };

static unsigned			 menu_count = 0;
static unsigned			 menua_count = 0;
static unsigned			 menuag_count = 0;

static void
gui_pbar_clear(void)
{
  nd_gui_pbar_clear(2000);
}


unsigned int
nd_gui_init(int argc, char* argv[])
{
	GError *err = NULL;
	unsigned res = 0;
	
	// GTK init
	gtk_set_locale();
	gtk_init(&argc, &argv);
	
	// Get GTKBuilder interface
	nd_builder = gtk_builder_new ();
	if (nd_builder == NULL) {
		D(("Failed to create GTK builder!\n"));
		return 1;
	}
	res = gtk_builder_add_from_file (nd_builder, ND_GTK_BUILDER_FILE, &err);
	if (res == 0) {
		D(("%s\n", err->message));
		g_error_free(err);
		return 2;
	}
	
	/*
	 * Frequently used pointers should be conveniently global as well.
	 */
	/* main window */
	ND_GTK_GET_TYPE(GTK_WINDOW, nd_toplevel_window, nd_builder, "toplevel");
	/* main menu */
	ND_GTK_GET_TYPE(GTK_UI_MANAGER, nd_ui_manager, nd_builder, "uimanager1");
	
	// Connect signals and post-init setup
	gtk_builder_connect_signals(nd_builder, NULL);
	nd_gui_init_setup();
	
	return 0;
}


void
nd_gui_shutdown()
{
	g_object_unref( G_OBJECT(nd_builder) );
}


void
nd_gui_init_setup(void)
{
  int        i;
  GtkWidget *win;
  GtkWidget *w;
  GtkAction *a;
  GtkStyle  *gs;
  LND_PacketIteratorObserver *ob;

  D_ENTER;

  // Pixmaps
  add_pixmap_directory (PACKAGE_DATA_DIR "/" VERSION_MAJOR "/pixmaps");
  add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
  gtk_window_set_default_icon_from_file("./pixmaps/netdude-icon.png", NULL);

  /** FIXME:
   * Is this dummy entry used to generate new entries?  If so we'll need
   * to find a new method to do this, because gtk-builder-convert removes
   * this entry altogether.
   */
  /* Hide the dummy entry in the protocols menu */
//   ND_GTK_GET_WIDGET(w, nd_builder, "proto_dummy");
//   gtk_widget_hide(w);

  /* No traces are loaded yet -- hide the traces notebook. */
//   w = GTK_WIDGET( gtk_buildable_get_internal_child(
  ND_GTK_GET_WIDGET(w, nd_builder, "traces_notebook");
  gtk_widget_hide(w);

  /* Initialize the global progress bar pointer */
  ND_GTK_GET_TYPE(GTK_PROGRESS_BAR, pbar, nd_builder, "progressbar");
  gtk_progress_bar_set_activity_blocks(pbar, PBAR_ACTIVITY_BLOCKS);

  /* Pixmap and Color stuff below */
  ND_GTK_GET_WIDGET(w, nd_builder, "toplevel");
  gs = gtk_widget_get_style(w);
  win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_realize(win);
  incomplete_pmap = gdk_pixmap_create_from_xpm(win->window, &incomplete_mask,
                                               &gs->bg[GTK_STATE_NORMAL],
                                               PACKAGE_DATA_DIR "/" VERSION_MAJOR "/pixmaps/incomplete.xpm");

  /* Init red and yellow: */
  for (i = 0; i < 5; i++)
  {
    bg[i] = gs->bg[i];
    red[i] = gs->bg[i];
    red[i].red = (2 * red[i].red) > 65535 ? 65535 : 2 * red[i].red;
    if (red[i].red == 0)
      red[i].red = 32768;
    red[i].green /=  2;
    red[i].blue /= 2;
  }

  for (i = 0; i < 5; i++)
  {
    yellow[i] = gs->bg[i];
    yellow[i].green = (2 * yellow[i].green) > 65535 ? 65535 : 2 * yellow[i].green;
    yellow[i].red = (2 * yellow[i].red) > 65535 ? 65535 : 2 * yellow[i].red;

    if (yellow[i].green == 0)
      yellow[i].green = 32768;

    if (yellow[i].red == 0)
      yellow[i].red = 32768;

    yellow[i].blue /=  2;
  }

  /* Create tooltips, if necessary. */
//   if (! (tt = gtk_object_get_data(GTK_OBJECT(nd_gtk_toplevel), "tooltips")))
//   {
//     tt = gtk_tooltips_new();
//     gtk_object_set_data (GTK_OBJECT (nd_gtk_toplevel), "tooltips", tt);
//     gtk_tooltips_enable(tt);
//   }

  /* Initialize the view indicator */
//   nd_gui_update_view_indicator();
//   nd_gui_update_area_indicator();

  /* Initialize the progress bar hooks from libnetdude, so that the GUI updates
   * the progress bar whenever libnetdude is iterating over packets.
   */
//   if ( (ob = libnd_pit_observer_new()))
//   {
//     ob->pit_init     = nd_gui_pbar_reset;
//     ob->pit_progress = nd_gui_pbar_inc;
//     ob->pit_clear    = gui_pbar_clear;
// 
//     libnd_pit_add_observer(ob);
//   }

  /* Initialize the debugging menu -- if compiled with debugging, show
   * the menu, otherwise hide it.
   */
#ifdef ND_DEBUG
  ND_GTK_GET_TYPE(GTK_ACTION, a, nd_builder, "netdude_output");
  gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(a), nd_runtime_options.debug);
  ND_GTK_GET_TYPE(GTK_ACTION, a, nd_builder, "libnetdude_output");
  gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(a), libnd_runtime_options.debug);
  ND_GTK_GET_TYPE(GTK_ACTION, a, nd_builder, "pcapnav_output");
  gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(a), pcapnav_runtime_options.debug);
#else
  ND_GTK_GET_TYPE(GTK_ACTION, a, nd_builder, "debugging");
  gtk_action_set_visible(a, FALSE);
#endif

  D_RETURN;
}


void
nd_gui_sync_edit_menu(void)
{
//   LND_Trace  *trace   = NULL;
//   LND_Packet *current = NULL;
//   GtkWidget  *button;
//   gboolean has_packets = FALSE;
// 
//   trace = nd_trace_registry_get_current();
//   if (trace)
//     {
//       current = nd_trace_get_current_packet(trace);
//       has_packets = (trace->tpm->current->pl != NULL);
//     }
// 
//   ND_GTK_GET(button, nd_toplevel_window, "packet_paste");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (nd_clipboard_occupied() && trace));  
//   ND_GTK_GET(button, nd_toplevel_window, "packet_delete");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "packet_copy");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "packet_cut");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "packet_select_all");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), ((trace && has_packets) ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "packet_unselect_all");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current && libnd_tp_get_sel_size(trace->tpm->current) > 0));
//   ND_GTK_GET(button, nd_toplevel_window, "filtering");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (trace? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "packet_filter");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "packet_unfilter");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "trace_areas");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (trace? TRUE : FALSE));
}


// void
// nd_gui_sync_go_menu(void)
// {
//   LND_Trace  *trace   = NULL;
//   LND_Packet *current = NULL;
//   GtkWidget  *button;
// 
//   trace = nd_trace_registry_get_current();
// 
//   if (trace)
//     current = nd_trace_get_current_packet(trace);
//   
//   ND_GTK_GET(button, nd_toplevel_window, "next_packet");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "previous_packet");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "next_selected");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "previous_selected");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "next_with_same_protocol");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "previous_with_same_protocol");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "next_unfiltered");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "previous_unfiltered");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (current ? TRUE : FALSE));
//   ND_GTK_GET(button, nd_toplevel_window, "other_trace_area");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), (trace && trace->needs_nav ? TRUE : FALSE));
// }
// 
// 
// void
// nd_gui_sync_file_menu(void)
// {
//   GtkWidget *button;
//   gboolean   enable;
// 
//   enable = nd_trace_registry_get_current() ? TRUE : FALSE;
// 
//   ND_GTK_GET(button, nd_toplevel_window, "save");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), enable);
//   ND_GTK_GET(button, nd_toplevel_window, "save_as");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), enable);
//   ND_GTK_GET(button, nd_toplevel_window, "info");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), enable);
//   ND_GTK_GET(button, nd_toplevel_window, "close");
//   gtk_widget_set_sensitive(GTK_WIDGET(button), enable);
// }
// 
// static void
// gui_sync_protocol_cb(LND_Protocol *proto, void *user_data)
// {
//   ND_Protocol *proto_gui = nd_proto_get(proto);
// 
//   if (!proto_gui || !proto_gui->proto_menu_item)
//     return;
// 
//   gtk_widget_set_sensitive(proto_gui->proto_menu_item, user_data ? TRUE : FALSE);  
// }
// 
// void
// nd_gui_sync_protocol_menu(void)
// {
//   LND_Trace *trace;
// 
//   trace = nd_trace_registry_get_current();
//   libnd_proto_registry_foreach_proto(gui_sync_protocol_cb, trace);
// }
// 
// void
// nd_gui_sync_menus(void)
// {
//   D_ENTER;
//   nd_gui_sync_edit_menu();
//   nd_gui_sync_file_menu();
//   nd_gui_sync_go_menu();
//   nd_gui_sync_protocol_menu();
//   D_RETURN;
// }
// 
// 
// void
// nd_gui_show_packet_menu(GdkEventButton *event)
// {
//   GtkWidget *menu;
// 
//   /* Let's grab the edit menu from the main window: */
//   ND_GTK_GET(menu, nd_toplevel_window, "edit_menu");
//   
//   /* Update its settings -- everything is registered with the
//      nd_toplevel_window window: */
//   nd_gui_sync_edit_menu();
// 
//   /* And show the menu :) */
//   gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
// 		 event->button, event->time);
// }
// 
// 
// static void
// iterator_menu_position_func(GtkMenu   *menu,
// 			    gint      *x,
// 			    gint      *y,
// 			    gpointer   user_data)
// {
//   LND_Trace *trace = (LND_Trace *) user_data;
//   ND_Trace *trace_gui;
//   GtkWidget *button;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   ND_GTK_GET(button, trace_gui->tab, "apply_button");
//   gdk_window_get_deskrelative_origin(button->window, x, y);
//   *y += button->allocation.height;
// 
//   return;
//   TOUCH(menu);
// }
// 
// 
// void
// nd_gui_show_iterator_mode_menu(GdkEventButton *event)
// {
//   LND_Trace *trace;
// 
//   return_if_no_current_trace(trace);
// 
//   if (!iterator_menu)
//     iterator_menu = create_trace_menu();
//     
//   nd_gui_iterator_mode_set(trace);
// 
//   gtk_menu_popup(GTK_MENU(iterator_menu), NULL, NULL,
// 		 iterator_menu_position_func, trace,
// 		 event->button, event->time);
// }


// void
// nd_gui_num_packets_set(void)
// {
//   LND_Trace       *trace;
//   char             s[MAXPATHLEN];
//   GtkWidget       *w;
// 
//   trace = nd_trace_registry_get_current();
// 
//   if (!trace)
//     s[0] = '\0';
//   else if (trace->tpm->current->num_packets == 1)
//     g_snprintf(s, MAXPATHLEN, _("1 packet."));
//   else
//     g_snprintf(s, MAXPATHLEN, _("%i packets."),
// 	       trace->tpm->current->num_packets);
//   
//   ND_GTK_GET(w, nd_toplevel_window, "num_packets_label");
//   gtk_label_set_text(GTK_LABEL(w), s);
// }
// 
// 
// void
// nd_gui_set_trace_status(LND_Trace *trace)
// {
//   GtkWidget *button;
//   GtkWidget *pixmap_red, *pixmap_green;
//   ND_Trace  *trace_gui;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   ND_GTK_GET(button, trace_gui->tab, "close_button");
//   ND_GTK_GET(pixmap_green, trace_gui->tab, "pixmap_green");
//   ND_GTK_GET(pixmap_red, trace_gui->tab, "pixmap_red");
// 
//   if (pixmap_green->parent)
//     gtk_container_remove(GTK_CONTAINER(button), pixmap_green);
// 
//   if (pixmap_red->parent)
//     gtk_container_remove(GTK_CONTAINER(button), pixmap_red);
// 
//   if (trace->dirty)
//     gtk_container_add(GTK_CONTAINER(button), pixmap_red);
//   else
//     gtk_container_add(GTK_CONTAINER(button), pixmap_green);
// }


void
nd_gui_iterator_mode_set(LND_Trace *trace)
{
// 	GtkWidget *button, *w;
// 	GtkWidget *pixmap_sel, *pixmap_part, *pixmap_all;
// 	ND_Trace *trace_gui = nd_trace_get(trace);
// 	
// 	if (!trace_gui)
// 		return;
// 	
// 	if (!iterator_menu)
// 		iterator_menu = create_trace_menu();
// 	
// 	ND_GTK_GET(button, trace_gui->tab, "apply_button");
// 	ND_GTK_GET(pixmap_sel,  trace_gui->tab, "pixmap_apply_sel");
// 	ND_GTK_GET(pixmap_part, trace_gui->tab, "pixmap_apply_part");
// 	ND_GTK_GET(pixmap_all,  trace_gui->tab, "pixmap_apply_all");
// 	
// 	if (pixmap_sel->parent)
// 		gtk_container_remove(GTK_CONTAINER(button), pixmap_sel);
// 	if (pixmap_part->parent)
// 		gtk_container_remove(GTK_CONTAINER(button), pixmap_part);
// 	if (pixmap_all->parent)
// 		gtk_container_remove(GTK_CONTAINER(button), pixmap_all);
// 	
// 	switch(trace->iterator_mode)
// 	{
// 		case LND_PACKET_IT_SEL_R:
// 		case LND_PACKET_IT_SEL_RW:
// 			ND_GTK_GET(w, iterator_menu, "apply_to_selection");
// 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), TRUE);
// 			gtk_container_add(GTK_CONTAINER(button), pixmap_sel);
// 			break;
// 		default:
// 			ND_GTK_GET(w, iterator_menu, "apply_to_trace_area");
// 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), TRUE);
// 			gtk_container_add(GTK_CONTAINER(button), pixmap_part);
// 	}
}


static void
gui_statusbar_set(const char *text, gboolean clear)
{
  static guint timeout_id;
  GtkLabel *l;

  if (!text)
    return;

  ND_GTK_GET_TYPE(GTK_LABEL, l, nd_builder, "statuslabel");
  gtk_label_set_text(l, text);

  while (gtk_events_pending())
    gtk_main_iteration();

  if (pbar_timeout_set)
    gtk_timeout_remove(timeout_id);

  if (clear)
    {
      timeout_id = gtk_timeout_add(STATUSBAR_TIMEOUT * 1000, nd_gui_statusbar_clear, NULL);
      pbar_timeout_set = TRUE;
    }
}


void 
nd_gui_statusbar_set(const char *text)
{
  gui_statusbar_set(text, TRUE);
}


void
nd_gui_statusbar_set_noclear(const char *text)
{
  gui_statusbar_set(text, FALSE);
}


gint
nd_gui_statusbar_clear(gpointer data)
{
  GtkLabel *l;

  ND_GTK_GET_TYPE(GTK_LABEL, l, nd_builder, "statuslabel");
  gtk_label_set_text(l, "");
  pbar_timeout_set = 0;

  return 0;
  data = NULL;
}


// void
// nd_gui_pbar_reset(int num_total)
// {
//   LND_Trace *trace;
//   pbar_current = 0;
//   
//   D_ENTER;
// 
//   if (num_total > 0)
//     {
//       D(("Progressbar initialized to %i steps.\n", num_total));
//       pbar_total = num_total;
//     }
//   else
//     {
//       if ( (trace = nd_trace_registry_get_current()))
// 	{
// 	  switch (trace->iterator_mode)
// 	    {
// 	    case LND_PACKET_IT_PART_R:
// 	    case LND_PACKET_IT_PART_RW:
// 	      pbar_total = trace->tpm->current->num_packets;
// 	      break;
// 	      
// 	    case LND_PACKET_IT_AREA_R:
// 	    case LND_PACKET_IT_AREA_RW:
// 	      pbar_total = trace->tpm->size;
// 	      break;
// 
// 	    case LND_PACKET_IT_SEL_R:
// 	    case LND_PACKET_IT_SEL_RW:
// 	    default:
// 	      pbar_total = libnd_tp_get_sel_size(trace->tpm->current);
// 	    }
// 	}
//     }
// 
//   nd_gui_pbar_clear(0);
// 
//   D_RETURN;
// }


void
nd_gui_pbar_inc(int num_inc)
{
  gfloat ratio;

  /* D_ENTER; */

  pbar_current += num_inc;

  if (pbar_current > pbar_total)
    pbar_current = pbar_total;

  if ( (ratio = (gfloat)pbar_current/(gfloat)pbar_total) > pbar_old_ratio + 0.01)
    {
      gtk_progress_bar_update(pbar, MIN(ratio, 1.0));

      while (gtk_events_pending())
        gtk_main_iteration();

      pbar_old_ratio = ratio;
    }

  /* D_RETURN; */
}


static gint
gui_pbar_clear_timeout(gpointer data)
{
  gtk_progress_bar_update(pbar, 0.0);
  pbar_old_ratio = -1.0;

  while (gtk_events_pending())
    gtk_main_iteration();

  return FALSE;
  TOUCH(data);
}

void
nd_gui_pbar_clear(int delay)
{
  gtk_progress_bar_update(pbar, 0.0);
  pbar_old_ratio = -1.0;

  gtk_timeout_add(delay, gui_pbar_clear_timeout, NULL);
}

static gint
gui_pbar_timeout(gpointer data)
{
  static guint step = 0;

  if (step > PBAR_ACTIVITY_BLOCKS)
    step = 0;

  gtk_progress_set_value(GTK_PROGRESS(pbar), step++);

  while (gtk_events_pending())
    gtk_main_iteration();

  if (pbar_activity_mode)
    return (TRUE); /* Let's get called again */

  nd_gui_pbar_clear(0);

  return (FALSE);
  data = NULL;
}


void
nd_gui_pbar_start_activity(void)
{
  gtk_progress_set_activity_mode(GTK_PROGRESS(pbar), TRUE);
  pbar_activity_mode = TRUE;
  gtk_timeout_add(100, gui_pbar_timeout, NULL);
}


void
nd_gui_pbar_stop_activity(void)
{
  gtk_progress_set_activity_mode(GTK_PROGRESS(pbar), FALSE);
  pbar_activity_mode = FALSE;
}


// void
// nd_gui_list_freeze(LND_Trace *trace)
// {
//   ND_Trace        *trace_gui;
// 
//   if (!trace || !trace->tpm || !trace->tpm->current)
//     D_RETURN;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   gtk_clist_freeze(GTK_CLIST(trace_gui->list));
// }
// 
// 
// void
// nd_gui_list_thaw(LND_Trace *trace)
// {
//   ND_Trace        *trace_gui;
// 
//   if (!trace || !trace->tpm || !trace->tpm->current)
//     D_RETURN;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   gtk_clist_thaw(GTK_CLIST(trace_gui->list));
// }


void
nd_gui_list_set_incomplete_column_visible(LND_Trace *trace, gboolean visible)
{
	ND_Trace *trace_gui;
	
	if (! (trace_gui = nd_trace_get(trace)))
		return;
	
	if (!trace_gui->list)
		return;
	
// 	gtk_clist_set_column_visibility(GTK_CLIST(trace_gui->list), 1, visible);
}


// void
// nd_gui_list_set_row_incomplete(LND_Trace *trace, int row, gboolean incomplete)
// {
//   ND_Trace *trace_gui;
//   GtkCList *clist;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   if (!trace_gui->list)
//     return;
// 
//   clist = GTK_CLIST(trace_gui->list);
// 
//   if (incomplete)
//     gtk_clist_set_pixmap(clist, row, 1, incomplete_pmap, incomplete_mask);
//   else
//     gtk_clist_set_text(clist, row, 1, "");
// }
// 
// 
// void
// nd_gui_list_set_row_filtered(LND_Trace *trace, int row, gboolean filtered)
// {
//   ND_Trace *trace_gui;
//   GtkCList *clist;
//   GtkStyle *gs;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   if (!trace_gui->list)
//     return;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   gs = gtk_widget_get_style(GTK_WIDGET(clist));
// 
//   if (filtered)
//     gtk_clist_set_foreground(clist, row, gs->mid);
//   else
//     gtk_clist_set_foreground(clist, row, gs->text);
// }


void
nd_gui_set_windowtitle(const char *filename)
{
  char       s[MAXPATHLEN];
  gchar     *result = (gchar *) filename;
  int        show_full_path;

  D_ENTER;

  if (!filename)
    {
      D(("Input error.\n"));
      D_RETURN;
    }

//   libnd_prefs_get_int_item(ND_DOM_NETDUDE, "show_full_path", &show_full_path);
  show_full_path = 0;

  if (!show_full_path)
    result = g_path_get_basename(filename);

  g_snprintf(s, MAXPATHLEN, "Netdude: %s", result);
  gtk_window_set_title(nd_toplevel_window, s);

  // clean-up
  if (!show_full_path)
    g_free(result);
}


static gint
gui_show_timestamp_timeout(gpointer data)
{
  GtkWidget *w;

  ND_GTK_GET_WIDGET(w, nd_builder, "timestamp_win");

  gtk_widget_show(w);

  return (0);
  data = NULL;
}


// void
// nd_gui_timestamp_schedule(GtkCList *clist,
// 			  GdkEventMotion *event)
// {
//   static GtkWidget *tooltip = NULL;
// 
//   LND_Packet *packet;
//   LND_Trace  *trace;
//   char        ts_text[MAXPATHLEN];
//   int         ptr_x, ptr_y, row;
//   int         pref_show_ts, pref_show_ts_abs;
//   float       pref_ts_delay; 
//   GtkWidget  *ts_label;
// 
// 
//   /* We won't show timestamps if any buttons are pressed
//      while moving around ... */
// 
//   if ((event->state & (GDK_BUTTON1_MASK |
// 		       GDK_BUTTON2_MASK |
// 		       GDK_BUTTON3_MASK |
// 		       GDK_BUTTON4_MASK |
// 		       GDK_BUTTON5_MASK)) != 0)
//     return;
// 
//   row = (event->y - clist->voffset) / (clist->row_height + 1);
// 
//   trace  = nd_trace_registry_get_current();
//   D_ASSERT_PTR(trace);
//   packet = libnd_tp_packet_get_nth(trace->tpm->current, row);
// 
//   if (!packet)
//     return;
// 
//   pref_show_ts = TRUE;
//   pref_show_ts_abs = FALSE;
//   pref_ts_delay = 0.5; 
// 
//   libnd_prefs_get_int_item(ND_DOM_NETDUDE, "show_timestamps", &pref_show_ts);
//   libnd_prefs_get_int_item(ND_DOM_NETDUDE, "show_timestamps_absolute", &pref_show_ts_abs);
//   libnd_prefs_get_flt_item(ND_DOM_NETDUDE, "timestamps_delay", &pref_ts_delay);
// 
//   if (!pref_show_ts)
//     return;
// 
//   if (tooltip)
//     gtk_widget_hide(tooltip);
// 
//   if (timestamp_set && pref_ts_delay > 0.1)
//     gtk_timeout_remove(timestamp_id);
// 
//   if (packet->prev && !pref_show_ts_abs)
//     {
//       struct bpf_timeval delta_last, delta_abs;
// 
//       TV_SUB(&packet->ph.ts, &packet->prev->ph.ts, &delta_last);
//       TV_SUB(&packet->ph.ts, &trace->tpm->current->start_ts, &delta_abs);
// 
//       g_snprintf(ts_text, MAXPATHLEN, "%li.%06lis, %li.%06lis (%lu.%lu)",
// 		 (long int) delta_abs.tv_sec, (long int) delta_abs.tv_usec,
// 		 (long int) delta_last.tv_sec, (long int) delta_last.tv_usec,
// 		 (long unsigned int) packet->ph.ts.tv_sec, (long unsigned int) packet->ph.ts.tv_usec);
//     }
//   else
//     {
//       int offset;
//       time_t tt = (time_t)packet->ph.ts.tv_sec;
// 
//       g_snprintf(ts_text, MAXPATHLEN, "%s", ctime(&tt));
//       offset = strlen(ts_text)-1;
//       g_snprintf(ts_text + offset, MAXPATHLEN, " +  %li usec (%lu.%lu)",
// 		 (long int) packet->ph.ts.tv_usec,
// 		 (long unsigned int) packet->ph.ts.tv_sec, (long unsigned) packet->ph.ts.tv_usec);
//     }
// 
//   /* If the packet is only partly captured, show
//      how many bytes are missing: */
//   if (packet->ph.len > packet->ph.caplen)
//     {
//       int offset = strlen(ts_text);
// 
//       g_snprintf(ts_text + offset, MAXPATHLEN - offset,
// 		 _(", %i bytes missing"), 
// 		 packet->ph.len - packet->ph.caplen);
//     }
// 
//   if (!tooltip)
//     {
//       tooltip = create_timestamp_window();
//       gtk_window_set_position(GTK_WINDOW(tooltip), GTK_WIN_POS_NONE);
//       gtk_object_set_data(GTK_OBJECT(nd_toplevel_window), "timestamp_win", tooltip);
//     }
// 
//   ND_GTK_GET(ts_label, tooltip, "timestamp_label");
//   gtk_label_set_text(GTK_LABEL(ts_label), ts_text);
// 
//   /* HELP! What's the correct way to ensure that w->allocation.width has the correct
//      size now? I haven't been able to figure it out. Since our window's content is
//      simple (just the line of text), let's use the width of the text string as
//      an approximation.
//   */
// 
//   gtk_widget_realize(tooltip);
// 
//   gdk_window_get_pointer(NULL, &ptr_x, &ptr_y, NULL);
//   gtk_widget_set_uposition(GTK_WIDGET(tooltip),
// 			   ptr_x - gdk_text_width(ts_label->style->font, ts_text, strlen(ts_text))/2,
// 			   ptr_y + 15);      
// 
// 
//   timestamp_id = gtk_timeout_add(pref_ts_delay * 1000,
// 				 gui_show_timestamp_timeout, NULL);
//   timestamp_set = TRUE;
// }


void
nd_gui_timestamp_hide(void)
{
//   GtkWidget *tooltip;

  if (timestamp_set)
    {
      gtk_timeout_remove(timestamp_id);
      timestamp_set = FALSE;
    }

//   tooltip = gtk_object_get_data(GTK_OBJECT(nd_toplevel_window), "timestamp_win");
//   if (tooltip)
//     gtk_widget_hide(tooltip);
}


static gint
gui_selection_descend_sort(gconstpointer a, gconstpointer b)
{
  if (GPOINTER_TO_UINT(a) < GPOINTER_TO_UINT(b))
    return 1;
  if (GPOINTER_TO_UINT(a) > GPOINTER_TO_UINT(b))
    return -1;

  return 0;
}


// void
// nd_gui_list_remove_selected_rows(LND_Trace *trace)
// {  
//   ND_Trace  *trace_gui;
//   GList     *l, *l2 = NULL, *l3 = NULL;
//   GtkCList  *clist;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   if (!trace_gui->list)
//     return;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   gtk_signal_handler_block_by_func(GTK_OBJECT(clist), on_trace_list_unselect_row, NULL);
//   gtk_clist_freeze(clist);
// 
//   if (clist->selection)
//     {      
//       for (l = clist->selection; l; l = l->next)
// 	l2 = g_list_append(l2, l->data);
// 
//       l2 = g_list_sort(l2, gui_selection_descend_sort);
// 
//       for (l3 = l2 ; l3; l3 = l3->next)
// 	gtk_clist_remove(clist, GPOINTER_TO_UINT(l3->data));
//     }
// 
//   gtk_clist_thaw(clist);
//   gtk_signal_handler_unblock_by_func(GTK_OBJECT(clist), on_trace_list_unselect_row, NULL);
// 
//   if (l2)
//     g_list_free(l2);
// }
// 
// 
// void
// nd_gui_list_remove_row(LND_Trace *trace, guint index)
// {
//   ND_Trace  *trace_gui;
//   GtkCList  *clist;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
// 
//   if (!trace_gui->list)
//     return;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   gtk_signal_handler_block_by_func(GTK_OBJECT(clist), on_trace_list_unselect_row, NULL);
//   gtk_clist_freeze(clist);
//   gtk_clist_remove(clist, index);
//   gtk_clist_thaw(clist);
//   gtk_signal_handler_unblock_by_func(GTK_OBJECT(clist), on_trace_list_unselect_row, NULL);
// }
// 
// 
// void
// nd_gui_list_insert_row(LND_Packet *packet, int index)
// {
//   ND_Trace  *trace_gui;
//   char       line[MAXPATHLEN];
//   char      *s[2];
// 
//   if (!packet || index < 0 || !packet->part)
//     return;
// 
//   if (! (trace_gui = nd_trace_get(libnd_packet_get_trace(packet))))
//     return;
// 
//   if (! libnd_tcpdump_get_packet_line(packet, line, MAXPATHLEN, TRUE))
//     {
//       g_snprintf(line, MAXPATHLEN, "[tcpdump I/O error]");
//       nd_dialog_message(_("Tcpdump I/O error"),
// 			_("An error occurred when obtaining tcpdump packet output.\n"),
// 			TRUE);
//     }
// 
//   s[0] = line;
//   s[1] = "";
// 
//   gtk_clist_insert(GTK_CLIST(trace_gui->list), index, s);
// }
// 
// 
// void
// nd_gui_list_clear(LND_Trace *trace)
// {
//   ND_Trace  *trace_gui;
//   GtkCList  *clist;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   if (!trace_gui->list)
//     return;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   gtk_signal_handler_block_by_func(GTK_OBJECT(clist), on_trace_list_unselect_row, NULL);
//   gtk_clist_freeze(clist);
//   gtk_clist_clear(clist);
//   gtk_clist_thaw(clist);
//   gtk_signal_handler_unblock_by_func(GTK_OBJECT(clist), on_trace_list_unselect_row, NULL);
// }
// 
// 
// static gboolean      
// gui_list_update_packet(const LND_Packet *packet, char *line, int len)
// {
//   int do_magic = 0;
//   guchar *raw_start, *raw_end;
// 
//   if (! libnd_tcpdump_get_packet_line(packet, line, len, TRUE))
//     {
//       nd_dialog_message(_("Tcpdump I/O error"),
// 			_("An error occurred when obtaining tcpdump packet output.\n"
// 			  "Not all packet ouput has been updated."),
// 			TRUE);
//       return FALSE;
//     }
// 
//   libnd_prefs_get_int_item(ND_DOM_NETDUDE, "show_magic_result", &do_magic);
// 
//   if (!do_magic)
//     return TRUE;
// 
//   raw_start = libnd_packet_get_data(packet, libnd_raw_proto_get(), 0);
//   raw_end = libnd_packet_get_data_end(packet, libnd_raw_proto_get(), 0);
// 
//   if (raw_start && raw_end)
//     {
//       char magicstr[512];
//       guchar *raw_start2 = NULL;
//       guchar *sep = (guchar*) strstr((const char*) raw_start, "\r\n\r\n");
// 
//       if (sep && sep + 4 != raw_end)
// 	{
// 	  char *m1, *m2;
// 	  raw_start2 = sep + 4;
// 
// 	  m1 = strdup(libnd_magic_buffer(raw_start, raw_start2 - raw_start));
// 	  m2 = strdup(libnd_magic_buffer(raw_start2, raw_end - raw_start2));
// 
// 	  if (m1[0] != '\0' || m2[0] != '\0')
// 	    {
// 	      snprintf(magicstr, 512, " [%s%s%s]",
// 		       m1[0] != '\0' ? m1 : "",
// 		       m1[0] != '\0' && m2[0] != '\0' ? "/" : "",
// 		       m2[0] != '\0' ? m2 : "");
// 	      magicstr[511] = '\0';
// 	      strncat(line, magicstr, len - strlen(line));
// 	      line[len-1] = '\0';
// 	    }
// 
// 	  g_free(m1);
// 	  g_free(m2);
// 	}
//       else
// 	{
// 	  const char *magic = libnd_magic_buffer(raw_start, raw_end - raw_start);
// 
// 	  if (magic[0] != '\0')
// 	    {
// 	      snprintf(magicstr, 512, " [%s]", magic);
// 	      magicstr[511] = '\0';
// 	      strncat(line, magicstr, len - strlen(line));
// 	      line[len-1] = '\0';
// 	    }
// 	}
//     }
// 
//   return TRUE;
// }
// 
// 
// void
// nd_gui_list_update(LND_Trace *trace)
// {
//   ND_Trace   *trace_gui;
//   GtkCList   *clist;
//   LND_Packet *packet;
//   char        line[MAXPATHLEN];
//   char       *s[2];
//   int         i;
// 
//   D_ENTER;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     D_RETURN;
// 
//   if (!trace_gui->list)
//     D_RETURN;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   gtk_clist_freeze(clist);
//   gtk_clist_clear(clist);    
//   gtk_clist_set_reorderable(clist, 1);
// 
//   nd_gui_statusbar_set(_("Updating tcpdump output..."));
//   nd_gui_pbar_reset(trace->tpm->current->num_packets);
// 
//   s[0] = line;
//   s[1] = "";
// 
//   for (packet = libnd_tpm_get_packets(trace->tpm), i = 0; packet; packet = packet->next, i++)
//     {
//       if (! gui_list_update_packet(packet, line, MAXPATHLEN))
// 	break;
// 
//       gtk_clist_append(clist, s);      
//       nd_gui_list_set_row_incomplete(trace, i, ! libnd_packet_is_complete(packet));
//       nd_gui_list_set_row_filtered(libnd_packet_get_trace(packet), i, libnd_packet_is_filtered(packet));      
//       nd_gui_pbar_inc(1);
//     }
// 
//   nd_gui_pbar_clear(0);    
//   gtk_clist_thaw(clist);
// 
//   D_RETURN;
// }
// 
// 
// void
// nd_gui_list_update_packet(const LND_Packet *packet)
// {
//   ND_Trace    *trace_gui;
//   int          index;
//   char         line[MAXPATHLEN];
// 
//   if (!packet || !packet->part)
//     return;
// 
//   if (! (trace_gui = nd_trace_get(libnd_packet_get_trace(packet))))
//     return;
// 
//   index = libnd_packet_get_index(packet);
//   gui_list_update_packet(packet, line, MAXPATHLEN);
//   gtk_clist_set_text(GTK_CLIST(trace_gui->list), index, 0, line);
// 
//   nd_gui_list_set_row_incomplete(libnd_packet_get_trace(packet), index,
// 				 ! libnd_packet_is_complete(packet));
// }
// 
// 
// void
// nd_gui_list_update_packet_at_index(const LND_Packet *p, int index)
// {
//   ND_Trace    *trace_gui;
//   char         line[MAXPATHLEN];
// 
//   if (!p)
//     return;
// 
//   if (! (trace_gui = nd_trace_get(libnd_packet_get_trace(p))))
//     return;
// 
//   if (index < 0)
//     {
//       nd_gui_list_update_packet(p);
//       return;
//     }    
// 
//   D_ASSERT_PTR(p->part);
//   D_ASSERT_PTR(trace_gui->list);
// 
//   if (! libnd_tcpdump_get_packet_line(p, line, MAXPATHLEN, TRUE))
//     {
//       g_snprintf(line, MAXPATHLEN, "[tcpdump I/O error]");
//       nd_dialog_message(_("Tcpdump I/O error"),
// 			_("An error occurred when obtaining tcpdump packet output.\n"),
// 			TRUE);
//     }
// 
//   gtk_clist_set_text(GTK_CLIST(trace_gui->list), index, 0, line);
// 
//   nd_gui_list_set_row_incomplete(libnd_packet_get_trace(p), index,
// 				 ! libnd_packet_is_complete(p));
// }
// 
// 
// void
// nd_gui_list_select_packet(LND_Trace *trace, guint index)
// {
//   ND_Trace *trace_gui;
//   GtkCList *clist;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   if (!trace_gui->list)
//     return;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   gtk_clist_select_row(clist, index, 0);  
// 
//   if (gtk_clist_row_is_visible(clist, index) != GTK_VISIBILITY_FULL)
//     gtk_clist_moveto(clist, index, 0, 0.5, 0);
// }
// 
// 
// void
// nd_gui_list_unselect_packet(LND_Trace *trace, guint index)
// {
//   ND_Trace *trace_gui;
//   GtkCList *clist;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   if (!trace_gui->list)
//     return;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   gtk_clist_unselect_row(clist, index, 0);  
// }
// 
// 
// void
// nd_gui_list_unselect_all(LND_Trace *trace, gboolean emit_signal)
// {
//   ND_Trace *trace_gui;
//   GtkCList *clist;
// 
//   D_ENTER;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     D_RETURN;
// 
//   if (! trace_gui->list)
//     D_RETURN;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   if (! emit_signal)
//     gtk_signal_handler_block_by_func(GTK_OBJECT(clist), on_trace_list_unselect_all, NULL);
//   gtk_clist_unselect_all(clist);  
//   if (! emit_signal)
//     gtk_signal_handler_unblock_by_func(GTK_OBJECT(clist), on_trace_list_unselect_all, NULL);
// 
//   D_RETURN;
// }
// 
// 
// void
// nd_gui_list_select_all(LND_Trace *trace, gboolean emit_signal)
// {
//   ND_Trace *trace_gui;
//   GtkCList *clist;
// 
//   D_ENTER;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     D_RETURN;
// 
//   if (!trace_gui->list)
//     D_RETURN;
// 
//   clist = GTK_CLIST(trace_gui->list);
//   if (! emit_signal)
//     gtk_signal_handler_block_by_func(GTK_OBJECT(clist), on_trace_list_select_all, NULL);
//   gtk_clist_select_all(clist);  
//   if (! emit_signal)
//     gtk_signal_handler_unblock_by_func(GTK_OBJECT(clist), on_trace_list_select_all, NULL);
// 
//   D_RETURN;
// }
// 
// 
// static gboolean
// gui_update_line_cb(LND_Packet *packet,
// 		   LND_ProtoData *pd,
// 		   void *user_data)
// {
//   char *line = (char *) user_data;
// 
//   if (!packet || !pd)
//     return TRUE;
// 
//   if (pd->inst.proto->is_stateful)
//     pd->inst.proto->update_tcpdump_line(packet, line);
// 
//   return TRUE;
// }
// 
// 
// void
// nd_gui_list_update_packet_state(const LND_Packet *packet)
// {
//   ND_Trace    *trace_gui;
//   int          index;
//   char        *line;
//   char         buf[MAXPATHLEN];
// 
//   if (!packet)
//     return;
// 
//   if (! (trace_gui = nd_trace_get(libnd_packet_get_trace(packet))))
//     return;
// 
//   D_ASSERT_PTR(trace_gui->list);
// 
//   index = libnd_packet_get_index(packet);
// 
//   gtk_clist_get_text(GTK_CLIST(trace_gui->list), index, 0, &line);
//   g_snprintf(buf, MAXPATHLEN, line);
// 
//   libnd_packet_foreach_proto((LND_Packet *) packet,
// 			     gui_update_line_cb,
// 			     buf);
// 
//   gtk_clist_set_text(GTK_CLIST(trace_gui->list), index, 0, buf);
// }
// 
// 
// void
// nd_gui_list_update_packet_state_at_index(const LND_Packet *packet, int index)
// {
//   ND_Trace    *trace_gui;
//   char        *line = NULL;
//   char         buf[MAXPATHLEN];
// 
//   if (!packet)
//     return;
// 
//   if (index < 0)
//     {
//       nd_gui_list_update_packet_state(packet);
//       return;
//     }    
// 
//   if (! (trace_gui = nd_trace_get(libnd_packet_get_trace(packet))))
//     return;
// 
//   D_ASSERT_PTR(trace_gui->list);
// 
//   gtk_clist_get_text(GTK_CLIST(trace_gui->list), index, 0, &line);
//   if (line)
//     {
//       g_snprintf(buf, MAXPATHLEN, line);
// 
//       libnd_packet_foreach_proto((LND_Packet *) packet,
// 				 gui_update_line_cb,
// 				 buf);
// 
//       gtk_clist_set_text(GTK_CLIST(trace_gui->list), index, 0, buf);
//     }
// }


static GtkWidget   *
gui_new_trace_list(void)
{
	GtkListStore		 *store;
	GtkTreeIter			  iter;
	GtkCellRenderer		 *renderer;
	GtkTreeViewColumn	 *column = NULL;
	GtkWidget			 *trace_list = NULL;
	
	trace_list = gtk_tree_view_new();
	
	
	/* --- Column #1 --- */
	
	column = gtk_tree_view_column_new();
	
	gtk_tree_view_column_set_title(column, list_titles[0]);
	
	gtk_tree_view_column_set_resizable(column, TRUE);
	
	/* pack tree view column into tree view */
	gtk_tree_view_append_column(GTK_TREE_VIEW(trace_list), column);
	
	renderer = gtk_cell_renderer_text_new();
	
	/* pack cell renderer into tree view column */
	gtk_tree_view_column_pack_start(column, renderer, TRUE);
	
	/* connect 'text' property of the cell renderer to
	 *  model column that contains the tcpdump log */
	gtk_tree_view_column_add_attribute(column, renderer, "text", 0);
	
	
	/* --- Column #2 --- */
	
	column = gtk_tree_view_column_new();
	
	gtk_tree_view_column_set_title(column, list_titles[1]);
	
	gtk_tree_view_column_set_resizable(column, TRUE);
	
	/* pack tree view column into tree view */
	gtk_tree_view_append_column(GTK_TREE_VIEW(trace_list), column);
	
	renderer = gtk_cell_renderer_text_new();
	
	/* pack cell renderer into tree view column */
	gtk_tree_view_column_pack_start(column, renderer, TRUE);
	
	/* connect 'text' property of the cell renderer */
	gtk_tree_view_column_add_attribute(column, renderer, "text", 0);

	/* make a model to fill some test data */	
	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
	
	/* append a row and fill in some data */
	gtk_list_store_append (store, &iter);
	gtk_list_store_set (store, &iter,
						0, "Test!",
						1, "Testinnnggg! :D",
						-1);
	
	/* append another row and fill in some data */
	gtk_list_store_append (store, &iter);
	gtk_list_store_set (store, &iter,
						0, "More roowwss",
						1, "please!!",
						-1);
	
	gtk_tree_view_set_model(GTK_TREE_VIEW(trace_list), store);
	
	/* The tree view has acquired its own reference to the
	*  model, so we can drop ours. That way the model will
	*  be freed automatically when the tree view is destroyed */
	
	g_object_unref(store);
	
	gtk_widget_show(trace_list);
	
	return trace_list;
}


// static GtkWidget   *
// gui_new_trace_list(void)
// {
// 	GtkWidget *trace_list;
// 	
// 	trace_list = gtk_clist_new_with_titles(2, list_titles);
// 	
// 	/*
// 	GTK_CLIST_CLASS_FW(GTK_CLIST(trace_list))->select_all = gui_gtk_clist_select_all;
// 	GTK_CLIST_CLASS_FW(GTK_CLIST(trace_list))->unselect_all = gui_gtk_clist_unselect_all;
// 	*/
// 	gtk_clist_set_column_justification(GTK_CLIST(trace_list), 1, GTK_JUSTIFY_CENTER);
// 	gtk_clist_set_column_resizeable(GTK_CLIST(trace_list), 0, FALSE);
// 	gtk_clist_set_column_visibility(GTK_CLIST(trace_list), 1, FALSE);
// 	gtk_clist_set_reorderable(GTK_CLIST(trace_list), TRUE);
// 	gtk_clist_set_use_drag_icons(GTK_CLIST(trace_list), FALSE);
// 	
// 	gtk_widget_show (trace_list);
// // 	gtk_widget_set_events (trace_list, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
// // 	gtk_clist_set_column_width (GTK_CLIST (trace_list), 1, 80);
// // 	gtk_clist_set_selection_mode (GTK_CLIST (trace_list), GTK_SELECTION_EXTENDED);
// // 	gtk_clist_column_titles_show (GTK_CLIST (trace_list));
// // 	gtk_clist_set_shadow_type (GTK_CLIST (trace_list), GTK_SHADOW_NONE);
// // 	
// // 	nd_gui_add_monowidth_widget(trace_list);
// // 	
// // 	gtk_clist_column_titles_passive(GTK_CLIST(trace_list));
// // 	
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "select_row",
// // 						GTK_SIGNAL_FUNC (on_trace_list_select_row),
// // 						NULL);
// // 	gtk_signal_connect_after (GTK_OBJECT (trace_list), "row_move",
// // 					GTK_SIGNAL_FUNC (on_trace_list_row_move),
// // 					NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "button_press_event",
// // 						GTK_SIGNAL_FUNC (on_trace_list_button_press_event),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "unselect_row",
// // 						GTK_SIGNAL_FUNC (on_trace_list_unselect_row),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "end_selection",
// // 						GTK_SIGNAL_FUNC (on_trace_list_end_selection),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "select_all",
// // 						GTK_SIGNAL_FUNC (on_trace_list_select_all),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "unselect_all",
// // 						GTK_SIGNAL_FUNC (on_trace_list_unselect_all),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "size_allocate",
// // 						GTK_SIGNAL_FUNC (on_trace_list_size_allocate),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "motion_notify_event",
// // 						GTK_SIGNAL_FUNC (on_trace_list_motion_notify_event),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "leave_notify_event",
// // 						GTK_SIGNAL_FUNC (on_trace_list_leave_notify_event),
// // 						NULL);
// // 	gtk_signal_connect (GTK_OBJECT (trace_list), "key_press_event",
// // 						GTK_SIGNAL_FUNC (on_trace_list_key_press_event),
// // 						NULL);
// 	
// 	return trace_list;
// }


static GtkWidget   *
gui_new_trace_proto_notebook(void)
{
	GtkWidget *notebook;
	
	notebook = gtk_notebook_new();
	gtk_widget_show(notebook);
	gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
	gtk_widget_set_usize(notebook, -2, 180);
	gtk_container_set_border_width(GTK_CONTAINER(notebook), 5);
	
	return notebook;
}


void
nd_gui_trace_new_tab(LND_Trace *trace)
{
	ND_Trace  *trace_gui;
	GtkWidget *tab_content, *tab_label_content, *scrolledwin;
	GtkWidget *trace_list, *notebook, *label, *button, *pixmap;
	GtkTooltips *tt;
	const char *file;
	
	D_ENTER;
	
	if (! (trace_gui = nd_trace_get(trace)))
		D_RETURN;
	
// 	tt = gtk_object_get_data(GTK_OBJECT(nd_toplevel_window), "tooltips");
	
	/* Build tab: */
	
	tab_content = gtk_vpaned_new ();
	gtk_widget_ref (tab_content);
	gtk_widget_show (tab_content);
	gtk_paned_set_position (GTK_PANED (tab_content), 200);
	
	scrolledwin = gtk_scrolled_window_new (NULL, NULL);
	gtk_widget_ref (scrolledwin);
	g_object_set_data_full (G_OBJECT (tab_content), "scrolledwin", scrolledwin,
					(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (scrolledwin);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
					GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_paned_pack1 (GTK_PANED (tab_content), scrolledwin, TRUE, TRUE);
	
	trace_list = gui_new_trace_list();
	gtk_widget_ref (trace_list);
	g_object_set_data_full (G_OBJECT (tab_content), "trace_list", trace_list,
					(GtkDestroyNotify) gtk_widget_unref);
	gtk_container_add (GTK_CONTAINER (scrolledwin), trace_list);
	/* gtk_paned_add1 (GTK_PANED (tab_content), trace_list); */
	
	notebook = gui_new_trace_proto_notebook();
	gtk_widget_ref (notebook);
	g_object_set_data_full (G_OBJECT (tab_content), "notebook", notebook,
					(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show(notebook);
	gtk_paned_pack2 (GTK_PANED (tab_content), notebook, FALSE, TRUE);
	
// 	gtk_signal_connect (GTK_OBJECT (notebook), "switch_page",
// 						GTK_SIGNAL_FUNC (on_protos_notebook_switch_page),
// 						notebook);
// 	
	g_object_set_data(G_OBJECT(tab_content), "trace", trace);
	g_object_set_data(G_OBJECT(notebook), "trace", trace);
	
	/* Build tab label: */
	if (trace->filename)
		file = g_basename(trace->filename);
	else
		file = trace->unnamed;
	
	/* Put everything in a tab in an hbox: */
	
	tab_label_content = gtk_hbox_new (FALSE, 0);
	gtk_widget_ref (tab_label_content);
	g_object_set_data_full (G_OBJECT (tab_content), "tab_label_content",
					tab_label_content, (GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (tab_label_content);
	
	/* Okay -- I want to have a tooltip with the  full file name on this
		tab. Label's don't work with tooltips, so I have to wrap the
		label in an event box. But if I do that, the tabs don't get
		switched by clicking on the label, and worse, they get drawn
		differently. I'll comment this out for now.
	
	eb = gtk_event_box_new();
	gtk_widget_show(eb);
	gtk_box_pack_start (GTK_BOX (tab_label_content), eb, TRUE, TRUE, 0);
	
	tt = gtk_object_get_data(GTK_OBJECT(nd_toplevel_window), "tooltips");
	gtk_tooltips_set_tip (GTK_TOOLTIPS(tt), eb, trace->filename, NULL);
	*/
	
	/* First thing in the box is the label containing the file name: */
	
	label = gtk_label_new (file);
	gtk_widget_ref (label);
	g_object_set_data_full (G_OBJECT (tab_content), "tab_label", label,
					(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (label);
	gtk_container_add(GTK_CONTAINER(tab_label_content), label);
	gtk_misc_set_padding (GTK_MISC (label), 8, 0);
	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
	
	
// 	/* Then there's the button with the apply-to setting: */
// 	
// 	pixmap = create_pixmap (tab_label_content, "apply_to_sel.xpm");
// 	gtk_widget_ref (pixmap);
// 	gtk_object_set_data_full (GTK_OBJECT (tab_content), "pixmap_apply_sel", pixmap,
// 					(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_widget_show (pixmap);
// 	gtk_misc_set_padding (GTK_MISC (pixmap), 0, 0);
// 	gtk_pixmap_set_build_insensitive (GTK_PIXMAP (pixmap), FALSE);
// 	
// 	
// 	pixmap = create_pixmap (tab_label_content, "apply_to_part.xpm");
// 	gtk_widget_ref (pixmap);
// 	gtk_object_set_data_full (GTK_OBJECT (tab_content), "pixmap_apply_part", pixmap,
// 					(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_widget_show (pixmap);
// 	gtk_misc_set_padding (GTK_MISC (pixmap), 0, 0);
// 	gtk_pixmap_set_build_insensitive (GTK_PIXMAP (pixmap), FALSE);
// 	
// 	
// 	pixmap = create_pixmap (tab_label_content, "apply_to_all.xpm");
// 	gtk_widget_ref (pixmap);
// 	gtk_object_set_data_full (GTK_OBJECT (tab_content), "pixmap_apply_all", pixmap,
// 					(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_widget_show (pixmap);
// 	gtk_misc_set_padding (GTK_MISC (pixmap), 0, 0);
// 	gtk_pixmap_set_build_insensitive (GTK_PIXMAP (pixmap), FALSE);
// 	
// 	
// 	button = gtk_button_new();
// 	gtk_container_add (GTK_CONTAINER (button), pixmap);
// 	gtk_widget_ref (button);
// 	gtk_object_set_data_full (GTK_OBJECT (tab_content), "apply_button", button,
// 					(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
// 				GTK_SIGNAL_FUNC (on_trace_menu_press_event),
// 				NULL);
// 	gtk_tooltips_set_tip(tt, button, _("Packet Iteration Mode"), NULL);
// 	gtk_widget_show (button);
// 	gtk_box_pack_start (GTK_BOX (tab_label_content), button, FALSE, FALSE, 0);  
// 	
// 	
// 	/* And the close button, with two pixmaps depending on the trace's state: */
// 	
// 	pixmap = create_pixmap (tab_label_content, "delete.xpm");
// 	gtk_widget_ref (pixmap);
// 	gtk_object_set_data_full (GTK_OBJECT (tab_content), "pixmap_red", pixmap,
// 					(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_widget_show (pixmap);
// 	gtk_misc_set_padding (GTK_MISC (pixmap), 0, 0);
// 	gtk_pixmap_set_build_insensitive (GTK_PIXMAP (pixmap), FALSE);
// 	
// 	pixmap = create_pixmap (tab_label_content, "delete_okay.xpm");
// 	gtk_widget_ref (pixmap);
// 	gtk_object_set_data_full (GTK_OBJECT (tab_content), "pixmap_green", pixmap,
// 					(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_widget_show (pixmap);
// 	gtk_misc_set_padding (GTK_MISC (pixmap), 0, 0);
// 	gtk_pixmap_set_build_insensitive (GTK_PIXMAP (pixmap), FALSE);
// 	
// 	button = gtk_button_new();
// 	gtk_container_add (GTK_CONTAINER (button), pixmap);
// 	gtk_widget_ref (button);
// 	gtk_object_set_data_full (GTK_OBJECT (tab_content), "close_button", button,
// 					(GtkDestroyNotify) gtk_widget_unref);
// 	
// 	gtk_signal_connect (GTK_OBJECT (button), "clicked",
// 						GTK_SIGNAL_FUNC (on_trace_close_clicked),
// 						trace);
// 	gtk_tooltips_set_tip(tt, button, _("Close Trace"), NULL);
// 	gtk_widget_show (button);
// 	gtk_box_pack_start (GTK_BOX (tab_label_content), button, FALSE, FALSE, 0);  
// 	
// 	gtk_paned_set_position(GTK_PANED(tab_content), nd_toplevel_window->allocation.height - 250);
	
	/* Hook up results: */
	
	trace_gui->tab = tab_content;
	trace_gui->tab_label = tab_label_content;
	trace_gui->list = trace_list;
	
	nd_gui_iterator_mode_set(trace);
	D_RETURN;
}


// void
// nd_gui_trace_set_name(LND_Trace *trace)
// {
//   ND_Trace   *trace_gui;
//   const char *sp;
//   GtkLabel   *label;
// 
//   D_ENTER;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     D_RETURN;
// 
//   ND_GTK_GET(label, trace_gui->tab, "tab_label");
// 
//   if (trace->filename)
//     sp = g_basename(trace->filename);
//   else
//     sp = trace->unnamed;
// 
//   gtk_label_set_text(label, sp);
//   D_RETURN;
// }


void
nd_gui_trace_add(LND_Trace *trace)
{
	ND_Trace  *trace_gui;
	GtkNotebook *notebook;
	GtkWidget *w;
	
	if (! (trace_gui = nd_trace_get(trace)))
		return;
	
	ND_GTK_GET_TYPE(GTK_NOTEBOOK, notebook, nd_builder,
			"traces_notebook");
	ND_GTK_GET_WIDGET(w, nd_builder, "background_vbox");
	
	if (GTK_WIDGET_VISIBLE(w))
	{
		gtk_widget_hide(w);
		gtk_widget_show(GTK_WIDGET(notebook));
	}
	
	gtk_notebook_append_page(notebook, trace_gui->tab, trace_gui->tab_label);
	
	/* Switch to the  new trace, calls nd_trace_registy_set_current()
		in the callback! */
	gtk_notebook_set_page(notebook, 
			gtk_notebook_page_num(notebook, trace_gui->tab));
	
	nd_gui_sync_edit_menu();
}


// void
// nd_gui_trace_remove(LND_Trace *trace)
// {
//   ND_Trace   *trace_gui;
//   GtkWidget  *notebook;
//   gint        trace_num;
// 
//   if (! (trace_gui = nd_trace_get(trace)))
//     return;
// 
//   ND_GTK_GET(notebook, nd_toplevel_window, "traces_notebook");
//   trace_num = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), trace_gui->tab);
//   gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), trace_num);
// 
//   /* We have a few special cases if we've closed all
//    * remaining trace files. In that case, show the
//    * background, and reset the window title.
//    */
//   if (gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) < 0)
//     {
//       GtkWidget *w;
// 
//       ND_GTK_GET(w, nd_toplevel_window, "background_vbox");
//       gtk_widget_show(w);
// 
//       gtk_widget_hide(notebook);
// 
//       gtk_window_set_title(GTK_WINDOW(nd_toplevel_window), "Netdude");
//     }
// 
//   nd_gui_num_packets_set();
//   nd_gui_sync_menus();
// }
// 
// 
// void
// nd_gui_widget_set_color(GtkWidget *widget, ND_GuiColor color)
// {
//   int i;
//   GtkRcStyle *rc_style = gtk_rc_style_new();
// 
//   switch (color)
//     {
//     case ND_COLOR_RED:
//       for (i=0; i<5; i++)
// 	{
// 	  rc_style->bg[i] = red[i];
// 	  rc_style->color_flags[i] = GTK_RC_BG;
// 	}
//       break;
// 
//     case ND_COLOR_YELLOW:
//       for (i=0; i<5; i++)
// 	{
// 	  rc_style->bg[i] = yellow[i];
// 	  rc_style->color_flags[i] = GTK_RC_BG;
// 	}
//       break;
// 
//     default:
//       for (i=0; i<5; i++)
// 	{
// 	  rc_style->bg[i] = bg[i];
// 	  rc_style->color_flags[i] = GTK_RC_BG;
// 	}
//     }
// 
//   /* FIXME: this leaks the widget's current style but I don't
//    * know how to fix it (do I? Shouldn't GTK take care of it?)
//    */
//   gtk_widget_modify_style(widget, rc_style);
// }


static void 
gui_menu_item_activate(GtkAction *menu_item,
		       gpointer user_data)
{
	LND_Trace        *trace;
	ND_Trace         *trace_gui;
	ND_MenuEntryCB    callback;
	int               value;
	
	/** FIXME: The commented code below is correct (with a few GTK+ 2.x
	 *			updates); this is just because we're using test
	 *			callbacks at the moment that don't do anything
	 */
	callback = (ND_MenuEntryCB) g_object_get_data(G_OBJECT(menu_item),
			"callback");
	value = GPOINTER_TO_INT(user_data);
	D_ASSERT_PTR(callback);
	if (callback)
		callback(NULL, NULL, value);
	
// 	return_if_no_current_trace(trace);
// 	
// 	if (! (trace_gui = nd_trace_get(trace)))
// 		return;
// 	
// 	callback = (ND_MenuEntryCB) gtk_object_get_data(GTK_OBJECT(menuitem),
// 			"callback");
// 	value = GPOINTER_TO_INT(user_data);
// 	
// 	D_ASSERT_PTR(callback);
// 	if (callback)
// 		callback(trace_gui->cur_packet,
// 				nd_trace_get_current_proto_header(trace),
// 				value);
}


static void
gui_add_menu_item(ND_GtkMenu *menu, ND_MenuData *data)
{
	char		  action_name[16] = "";
// 	GtkWidget	 *item;
	
	// Add a new action
// 	fprintf(stderr, "Creating action '%s_%u' for '%s'.\n", "menua", menu->item_action_count, data->label);
	snprintf(action_name, 16, "%s_%u", "menua", menua_count++);
	menu->item_actions = (GtkAction **)realloc(menu->item_actions,
			sizeof(GtkAction *) * (menu->item_action_count + 1));
	menu->item_actions[menu->item_action_count] = gtk_action_new(action_name,
			data->label, NULL, NULL);
	
	// Add the action to the action group
	gtk_action_group_add_action_with_accel(menu->action_group,
			menu->item_actions[menu->item_action_count], "");
	
	// Set the real callback
	g_object_set_data(G_OBJECT(menu->item_actions[menu->item_action_count]),
			"callback", data->callback);
	
	// Add a callback for the action
	g_signal_connect(G_OBJECT(menu->item_actions[menu->item_action_count++]),
			"activate", G_CALLBACK(gui_menu_item_activate),
			GINT_TO_POINTER((gint) data->value));
	
// 	item = gtk_menu_item_new_with_label (data->label);
// 	gtk_widget_ref (item);
// 	gtk_object_set_data_full (GTK_OBJECT (menu), data->label, item,
// 			(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_widget_show (item);
// 	gtk_container_add (GTK_CONTAINER (menu), item);
// 	
// 	gtk_object_set_data(GTK_OBJECT(item), "callback", data->callback);
// 	
// 	gtk_tooltips_set_tip(tt, item, data->tooltip, NULL);
// 	
// 	gtk_signal_connect (GTK_OBJECT (item), "activate",
// 			GTK_SIGNAL_FUNC (gui_menu_item_activate),
// 			GINT_TO_POINTER((gint) data->value));
}


ND_GtkMenu   *
nd_gui_create_menu(ND_MenuData *data)
{
	/** FIXME: Currently not cleaning ANY of this menu stuff
	 *			up!  Lots of g_free()'s to come in future
	 *			commits.
	 */
	char		  group_name[16] = "";
	ND_GtkMenu	 *menu = NULL;
	int        i;
	
	if (!data)
		return NULL;
	
	/* Create a new menu */
	menu = calloc(1, sizeof(ND_GtkMenu));
	
	/* Add a new action group */
	/** FIXME: Probably we need to do a boundary check on menuag_count
	 *			using UINT_MAX or something, but I don't think that
	 *			works the same on all *nix boxes, so we should check
	 *			into this.
	 */
	snprintf(group_name, 16, "%s_%u", "menuag", menuag_count++);
	menu->action_group = gtk_action_group_new(group_name);
	gtk_ui_manager_insert_action_group(nd_ui_manager, menu->action_group, 0);
	
	for (i = 0; data[i].label; i++)
		gui_add_menu_item(menu, &data[i]);
	
	return menu;
}


// /* Callback dispatcher -- receives callbacks on the Gtk level from
//    the protocol's field table, retrieves necessary data and calls
//    user's callback. */
// static void
// gui_proto_field_cb(GtkButton       *button,
// 		   gpointer         user_data)
// {
//   LND_Packet       *current;
//   LND_Trace        *trace;
//   LND_ProtoInfo    *pinf;
//   LND_ProtoInst    *pi;
//   ND_ProtoField    *field;
//   void       *header;
//   guint             offset;
// 
//   return_if_no_current_trace(trace);
// 
//   D_ENTER;
// 
//   field = (ND_ProtoField *) user_data;
//   D_ASSERT_PTR(field);
// 
//   pi = nd_trace_get_current_proto_inst(trace);
//   D_ASSERT_PTR(pi);
// 
//   pinf = nd_trace_get_proto_info(trace, pi->proto, pi->nesting);
//   D_ASSERT_PTR(pinf);
// 
//   if (! (current = nd_trace_get_current_packet(trace)))
//     {
//       D(("No currently selected packet!? -- aborting\n"));
//       return;
//     }
// 
//   D_ASSERT((nd_trace_get_current_proto_header(trace) ==
// 	    libnd_packet_get_data(current, pi->proto, pi->nesting)),
// 	   "Field callback dispatcher uses wrong packet header!");
// 
//   header = nd_trace_get_current_proto_header(trace);
//   offset = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(button), "offset"));
// 
//   if (field->callback)
//     {
//       nd_gui_proto_table_block_events(trace, pinf);
//       D(("Field %s callback on packet %p with offset %i\n",
// 	 field->label, current, offset));
//       field->callback(current, header, ((guchar*) header) + offset);
//       nd_gui_proto_table_unblock_events(trace, pinf);
//     }
// 
//   D_RETURN;
//   TOUCH(button);
// }
// 
// 
// /**
//  * gui_table_create_button - creates a button widget for a header field
//  * @parent: parent widget, for automatic destruction of new button
//  * @pinf: the protocol info that provides nesting info and the hash to store the buttons
//  * @field: the field for which the buttons is created
//  * @label: override label if the one given in @field isn't wanted (used
//  * for multi-line buttons)
//  * @offset: offset of the new button, stored with the button widget as "offset"
//  * @is_error: whether the button is in error state and thus painted red
//  * @set_data: whether to store the button in the packet info hashtable
//  */
// static GtkWidget *
// gui_table_create_button(GtkWidget *parent,
// 			LND_ProtoInfo *pinf,
// 			ND_ProtoField *field,
// 			const char *label,
// 			guint offset,
// 			gboolean is_error, gboolean set_data)
// {
//   GtkWidget *button = NULL;
//   const char *used_label = field->label;
// 
//   if (label)
//     used_label = label;
// 
//   switch (field->type)
//     {
//     case ND_FLG_FIELD:
//       button = gtk_toggle_button_new_with_label(used_label);
//       break;
// 
//     case ND_VAL_FIELD:
//     default:
//       button = gtk_button_new_with_label(used_label);
//     }
// 
//   gtk_tooltips_set_tip (GTK_TOOLTIPS(tt), button, field->tooltip, NULL);
// 
//   /* Arrange for automatic cleanup of the button: */
//   gtk_widget_ref(button);
//   gtk_widget_show(button);
//   gtk_object_set_data_full(GTK_OBJECT (parent), used_label,
// 			   button, (GtkDestroyNotify) gtk_widget_unref);
// 
//   /* Store the fields offset with the button */
//   gtk_object_set_data(GTK_OBJECT(button), "offset", GINT_TO_POINTER((offset >> 3)));
// 
//   /* If wanted, hook up the button in the packet info hash table */
//   if (set_data)
//     libnd_reg_set_data(pinf->registry, nd_proto_field_to_string(field), button);
// 
//   /* If the field provides a callback, hook it in, otherwise set
//    * the button insensitive so that it can't be pressed */
//   if (field->callback)
//     {
//       gtk_signal_connect(GTK_OBJECT (button), "clicked",
// 			 GTK_SIGNAL_FUNC (gui_proto_field_cb),
// 			 field);
//     }
//   else
//     {
//       gtk_widget_set_sensitive(button, FALSE);
//     }
// 
//   /* If something's wrong with it, paint it. */
//   nd_gui_widget_set_color(button, (is_error ? ND_COLOR_RED : ND_COLOR_BG));
// 
//   return button;
// }
// 
// 
// GtkWidget *
// nd_gui_proto_table_create(LND_Trace *trace,
// 			  LND_ProtoInfo *pinf)
// {
//   int           i, x, y, bpl, w_top, w_middle, w_bot, h_middle, largest = 0;
//   GtkWidget    *proto_table, *button;
//   char         *label;
//   guint         offset = 0;
//   LND_Protocol *proto;
//   ND_Protocol  *proto_gui;
// 
//   if (!trace || !pinf)
//     return NULL;
// 
//   proto = pinf->inst.proto;
//   proto_gui = nd_proto_get(proto);
//   D_ASSERT_PTR(proto_gui->fields);
//   bpl = proto_gui->header_width;
// 
//   /* Create the GUI tab for this protocol: ---------------------------- */
// 
//   /* Create the table itself: */
// 
//   proto_table = gtk_table_new (proto_gui->header_size / bpl, bpl, TRUE);
//   gtk_widget_show (proto_table);
//   gtk_container_set_border_width (GTK_CONTAINER (proto_table), 5);
// 
// /*   This is experimental stuff that could become a bit # indicator */
// /*   at some point. Right now it sucks, so it's commented out.  */
// /*
//   {
//     char s[MAXPATHLEN];
//     GtkWidget *bitnum;
//     for (i = 0; i < proto_gui->header_width; i += 4)
//       {
// 	g_snprintf(s, MAXPATHLEN, "%i", i);
// 	bitnum = gtk_label_new(s);
// 	gtk_widget_show(bitnum);
// 
// 	gtk_table_attach (GTK_TABLE (proto_table), bitnum,
// 			  i, i + 1,
// 			  0, 1,
// 			  (GtkAttachOptions) 0,
// 			  (GtkAttachOptions) 0, 0, 0);	
//       }
//   }
// */
// 
//   /* Iterate over all fixed header fields and hook buttons into
//    * the table: */
//   for (i = x = 0, y = 0; proto_gui->fields[i].label; i++)
//     {
//       w_middle = h_middle = w_bot = 0;      
//       w_top = proto_gui->fields[i].bits;
// 
//       if (x + w_top > bpl)
// 	w_top = bpl - x;
// 
//       if (w_top < proto_gui->fields[i].bits)
// 	{
// 	  w_middle = proto_gui->fields[i].bits - w_top;
// 	  h_middle = MAX(w_middle / bpl, 1);
// 
// 	  if (w_middle > bpl)
// 	    {
// 	      w_middle = bpl;	      
// 	      w_bot = proto_gui->fields[i].bits - w_top - h_middle * bpl;
// 	    }
// 
// 	  largest = (w_middle > w_top ? 1 : 0);
// 	}
// 
// 
//       label = (largest == 0 ? NULL : _("->"));
//       button = gui_table_create_button(proto_table, pinf, &proto_gui->fields[i],
// 				       label, offset, FALSE, TRUE);
// 
//       gtk_table_attach (GTK_TABLE (proto_table), button,
// 			x, x + w_top,
// 			y, y + 1,
// 			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
// 			(GtkAttachOptions) 0, 0, 0);
// 
//       x += w_top;
// 
//       if (w_middle)
// 	{
// 	  int options;
// 
// 	  x = 0;
// 	  y++;
// 	  label = (largest == 1 ? NULL : _("<-"));
// 	  options = (h_middle > 1 ? (GTK_EXPAND | GTK_FILL) : 0);
// 
// 	  button = gui_table_create_button(proto_table, pinf, &proto_gui->fields[i],
// 					   label, offset, FALSE, TRUE);
// 	  gtk_table_attach (GTK_TABLE (proto_table), button,
// 			    0, w_middle,
// 			    y, y + h_middle,
// 			    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
// 			    (GtkAttachOptions) options, 0, 0);
// 
// 	  x = w_middle;
// 	  y += h_middle;
// 	}
// 
//       if (w_bot)
// 	{
// 	  button = gui_table_create_button(proto_table, pinf, &proto_gui->fields[i],
// 					   _("<-"), offset, FALSE, FALSE);
// 	  gtk_table_attach (GTK_TABLE (proto_table), button,
// 			    0, w_bot,
// 			    y, y + 1,
// 			    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
// 			    (GtkAttachOptions) 0, 0, 0);
// 
// 	  x = w_bot;
// 	}
// 
//       if (x >= bpl)
// 	{
// 	  y++;
// 	  x = 0;
// 	}
// 
//       offset += proto_gui->fields[i].bits;
//     }
// 
//   return proto_table;
// }
// 
// 
// void
// nd_gui_proto_table_add(LND_Trace *trace,
// 		       LND_ProtoInfo *pinf,
// 		       ND_ProtoField *field,
// 		       void *data,
// 		       gboolean is_error)
// {
//   GList         *opt_widgets;
//   GtkWidget     *table, *button;
//   GtkTooltips   *tt;
//   int            w_top, w_middle, w_bot, h_middle, largest = 0;
//   int            x, y, offset;
//   char           label[MAXPATHLEN], *final_label;
//   LND_Protocol  *proto;
//   ND_Protocol   *proto_gui;
//   ND_ProtoInfo  *pinf_gui;
// 
//   if (!trace || !pinf)
//     return;
// 
//   proto = pinf->inst.proto;
//   pinf_gui  = nd_proto_info_get(pinf);
//   proto_gui = nd_proto_get(proto);
// 
//   opt_widgets = libnd_reg_get_data(pinf->registry, nd_proto_get_opt_key(proto));
// 
//   table = pinf_gui->proto_gui;
//   D_ASSERT_PTR(table);
//   ND_GTK_GET(tt, nd_toplevel_window, "tooltips");
// 
//   x = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(table), "options_x"));
//   y = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(table), "options_y"));
//   offset = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(table), "options_offset"));
// 
//   g_snprintf(label, MAXPATHLEN, field->label, data);
//   w_middle = h_middle = w_bot = 0;      
//   w_top = field->bits;
// 
//   if (x + w_top > proto_gui->header_width)
//     w_top = proto_gui->header_width - x;
// 
//   if (w_top < field->bits)
//     {
//       w_middle = field->bits - w_top;
//       h_middle = MAX(w_middle / proto_gui->header_width, 1);
// 
//       if (w_middle > proto_gui->header_width)
// 	{
// 	  w_middle = proto_gui->header_width;
// 	  w_bot = field->bits - w_top - h_middle * proto_gui->header_width;
// 	}
// 
//       largest = (w_middle > w_top ? 1 : 0);
//     }
// 
//   final_label = (largest == 0 ? label : _("->"));
// 
//   button = gui_table_create_button(table, pinf, field,
// 				   final_label, offset,
// 				   is_error, TRUE);
//   opt_widgets = g_list_append(opt_widgets, button);
// 
//   gtk_table_attach(GTK_TABLE(table), button,
// 		   x, x + w_top,
// 		   y, y + 1,
// 		   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
// 		   (GtkAttachOptions) 0, 0, 0);
// 
//   x += w_top;
// 
//   if (w_middle)
//     {
//       int options;
// 
//       y++;
//       final_label = (largest == 1 ? label : _("<-"));
//       options = (h_middle > 1 ? (GTK_EXPAND | GTK_FILL) : 0);
// 
//       button = gui_table_create_button(table, pinf, field,
// 				       final_label, offset,
// 				       FALSE, TRUE);
//       opt_widgets = g_list_append(opt_widgets, button);
//       gtk_table_attach (GTK_TABLE (table), button,
// 			0, w_middle,
// 			y, y + h_middle,
// 			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
// 			(GtkAttachOptions) options, 0, 0);
// 
//       x = w_middle;
//       y += h_middle;
//     }
// 
//   if (w_bot)
//     {
//       button = gui_table_create_button(table, pinf, field,
// 				       _("<-"), offset,
// 				       FALSE, FALSE);
//       opt_widgets = g_list_append(opt_widgets, button);
//       gtk_table_attach (GTK_TABLE (table), button,
// 			0, w_bot,
// 			y, y + 1,
// 			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
// 			(GtkAttachOptions) 0, 0, 0);
// 
//       x = w_bot;
//     }
// 
//   if (x == proto_gui->header_width)
//     {
//       x = 0;
//       y++;
//     }
// 
//   gtk_object_set_data(GTK_OBJECT(table), "options_x", GINT_TO_POINTER(x));
//   gtk_object_set_data(GTK_OBJECT(table), "options_y", GINT_TO_POINTER(y));
//   gtk_object_set_data(GTK_OBJECT(table), "options_offset", GINT_TO_POINTER(offset + field->bits));
// 
//   libnd_reg_set_data(pinf->registry, nd_proto_get_opt_key(proto), opt_widgets);
// }
// 
// 
// void
// nd_gui_proto_table_clear(LND_Trace *trace, LND_ProtoInfo *pinf)
// {
//   LND_Protocol *proto;
//   ND_Protocol  *proto_gui;
//   ND_ProtoInfo *pinf_gui;
//   GList        *opt_widgets;
//   GList        *l;
//   GtkWidget    *table;
//   int           x, y;
// 
//   if (!trace || !pinf)
//     return;
// 
//   proto = pinf->inst.proto;
//   pinf_gui = nd_proto_info_get(pinf);
//   proto_gui = nd_proto_get(proto);
// 
//   table = pinf_gui->proto_gui;
//   D_ASSERT_PTR(table);
// 
//   x = proto_gui->header_size % proto_gui->header_width;
//   y = proto_gui->header_size / proto_gui->header_width;
// 
//   gtk_object_set_data(GTK_OBJECT(table), "options_x", GINT_TO_POINTER(x));
//   gtk_object_set_data(GTK_OBJECT(table), "options_y", GINT_TO_POINTER(y));
//   gtk_object_set_data(GTK_OBJECT(table), "options_offset", GINT_TO_POINTER(proto_gui->header_size));
// 
//   if ( (opt_widgets = libnd_reg_get_data(pinf->registry, nd_proto_get_opt_key(proto))))
//     {
//       for (l = g_list_first(opt_widgets); l; l = g_list_next(l))
// 	{
// 	  gtk_container_remove(GTK_CONTAINER(table), GTK_WIDGET(l->data));
// 	  gtk_widget_destroy(GTK_WIDGET(l->data));
// 	}
// 
//       g_list_free(opt_widgets);
//       libnd_reg_del_data(pinf->registry, nd_proto_get_opt_key(proto));
//     }
// }
// 
// 
// void
// nd_gui_proto_table_block_events(LND_Trace * trace, LND_ProtoInfo *pinf)
// {
//   LND_Protocol *proto;
//   ND_Protocol  *proto_gui;
//   GtkWidget    *button;
//   int           i;
// 
//   if (!trace || !pinf)
//     return;
// 
//   proto = pinf->inst.proto;
//   proto_gui = nd_proto_get(proto);
// 
//   if (!proto_gui->fields)
//     return;
// 
//   for (i = 0; proto_gui->fields[i].label; i++)
//     {
//       if (proto_gui->fields[i].callback)
// 	{
// 	  button = libnd_reg_get_data(pinf->registry, nd_proto_field_to_string(&proto_gui->fields[i]));
// 	  D_ASSERT_PTR(button);
// 
// 	  gtk_signal_handler_block_by_func(GTK_OBJECT(button),
// 					   gui_proto_field_cb, &(proto_gui->fields[i]));
// 	}
//     }
// }
// 
// 
// void
// nd_gui_proto_table_unblock_events(LND_Trace * trace, LND_ProtoInfo *pinf)
// {
//   LND_Protocol *proto;
//   ND_Protocol  *proto_gui;
//   GtkWidget    *button;
//   int           i;
// 
//   if (!trace || !pinf)
//     return;
// 
//   proto = pinf->inst.proto;
//   proto_gui = nd_proto_get(proto);
// 
//   if (!proto_gui->fields)
//     return;
// 
//   for (i = 0; proto_gui->fields[i].label; i++)
//     {
//       if (proto_gui->fields[i].callback)
// 	{
// 	  button = libnd_reg_get_data(pinf->registry, nd_proto_field_to_string(&proto_gui->fields[i]));
// 	  D_ASSERT_PTR(button);
// 
// 	  gtk_signal_handler_unblock_by_func(GTK_OBJECT(button),
// 					     gui_proto_field_cb, &(proto_gui->fields[i]));
// 	}
//     }
// }


void
nd_gui_proto_menu_register(LND_Protocol *proto)
{
	ND_Protocol	 *proto_gui;
	char		  action_name[16] = "";
	char		 *proto_menu_path = "/ui/menubar1/proto";
	char		  new_menu_path[64] = "";
	unsigned	  i = 0;
	
// 	GtkWidget   *proto_menu;
// 	GtkWidget   *proto_menu_item;
// 	GList       *child;
// 	int          child_index;
// 	char        *label;
	
	if (!proto) {
		fprintf(stderr, "nd_gui_proto_menu_register: no proto...\n");
		return;
	}
	
	proto_gui = nd_proto_get(proto);
	
	if (!proto_gui->menu) {
		fprintf(stderr, "nd_gui_proto_menu_register: '%s' has no proto menu...\n", proto->name);
		return;
	}
	
	/* If the menu item already exists, we've been here before. */
	if (proto_gui->proto_menu_item) {
		fprintf(stderr, "nd_gui_proto_menu_register: '%s' menu exists...\n", proto->name);
		return;
	}
	
	D(("Hooking in menu for protocol %s\n", proto->name));
	
	// Add a new action
	snprintf(action_name, 16, "%s_%u", "menu", menu_count);
	proto_gui->menu->menu_action = gtk_action_new(action_name, proto->name, NULL, NULL);
	
	// Add the action to the action group
	gtk_action_group_add_action_with_accel(proto_gui->menu->action_group,
			proto_gui->menu->menu_action, "");
	
	// Add the protocol sub-menu to the primary protocol menu
	proto_gui->menu->menu_merge_id = gtk_ui_manager_new_merge_id(nd_ui_manager);
	gtk_ui_manager_add_ui(nd_ui_manager,
			proto_gui->menu->menu_merge_id, proto_menu_path, action_name,
			action_name, GTK_UI_MANAGER_MENU, FALSE);
	
	// Add the menu items to the protocol sub-menu
	snprintf(new_menu_path, 64, "%s/%s", proto_menu_path, action_name);
	for(i = 0; i < proto_gui->menu->item_action_count; ++i)
	{
		snprintf(action_name, 16, "%s", gtk_action_get_name(
				proto_gui->menu->item_actions[i]));
		proto_gui->menu->item_merge_ids = realloc(
				proto_gui->menu->item_merge_ids, sizeof(guint) *
				(proto_gui->menu->item_merge_id_count + 1));
		proto_gui->menu->item_merge_ids[proto_gui->menu->item_merge_id_count] =
				gtk_ui_manager_new_merge_id(nd_ui_manager);
		gtk_ui_manager_add_ui(nd_ui_manager,
				proto_gui->menu->item_merge_ids[
						proto_gui->menu->item_merge_id_count++],
				new_menu_path, action_name, action_name,
				GTK_UI_MANAGER_MENUITEM, FALSE);
	}
	
// 	ND_GTK_GET(proto_menu, nd_toplevel_window, "proto_menu");
// 	
// 	for (child_index = 0, child = GTK_MENU_SHELL(proto_menu)->children; child;
// 		child = g_list_next(child), child_index++)
// 		{
// 		if (! GTK_BIN(child->data)->child)
// 		break;
// 	
// 		gtk_label_get(GTK_LABEL(GTK_BIN(child->data)->child), &label);
// 	
// 		if (strcmp(proto->name, label) < 0)
// 		break;
// 		}
// 	
// 	proto_menu_item = gtk_menu_item_new_with_label (proto->name);
// 	proto_gui->proto_menu_item = proto_menu_item;
// 	
// 	gtk_widget_ref (proto_menu_item);
// 	gtk_object_set_data_full (GTK_OBJECT (nd_toplevel_window), proto->name, proto_menu_item,
// 								(GtkDestroyNotify) gtk_widget_unref);
// 	gtk_widget_show(proto_menu_item);
// 	gtk_menu_insert(GTK_MENU(proto_menu), proto_menu_item, child_index);
// 	gtk_widget_show(proto_gui->menu);
// 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (proto_menu_item), proto_gui->menu);
}


// void
// nd_gui_add_monowidth_widget(GtkWidget *widget)
// {
//   char         *fontname;
//   GtkStyle     *style;
// 
//   if (!widget)
//     return;
// 
//   if (!libnd_prefs_get_str_item(ND_DOM_NETDUDE, "font_mono", &fontname))
//     fontname = "-*-courier-medium-r-normal-*-*-100-*-*-m-*-*";
// 
//   style = gtk_style_copy(gtk_widget_get_style(widget));
//   gdk_font_unref(style->font);
//   style->font = gdk_font_load (fontname);
//   gtk_widget_set_style(widget, style);
// 
//   if (GTK_IS_CLIST(widget))
//     {
//       gtk_clist_set_row_height(GTK_CLIST(widget),
//       			       widget->style->font->ascent +
// 			       widget->style->font->descent + 2);
// 
//       /* This is a workaround for what appears to be a bug in
// 	 the clist code -- the vertical font alignment isn't
// 	 set correctly sometimes: */
//       GTK_CLIST(widget)->row_center_offset = widget->style->font->ascent + 1.5;
//     }
// 
//   gtk_widget_queue_draw(widget);
//   while (gtk_events_pending())
//     gtk_main_iteration();
// 
//   if (g_list_index(monowidth_widgets, widget) < 0)
//     monowidth_widgets = g_list_prepend(monowidth_widgets, widget);
// }
// 
// 
// void
// nd_gui_del_monowidth_widget(GtkWidget *widget)
// {
//   GList *l;
// 
//   if (!widget)
//     return;
// 
//   if ( (l = g_list_find(monowidth_widgets, widget)))
//     monowidth_widgets = g_list_remove_link(monowidth_widgets, l);
// }
// 
// 
// void
// nd_gui_update_monowidth_widgets(void)
// {
//   GList *l;
// 
//   for (l = monowidth_widgets; l; l = g_list_next(l))
//     nd_gui_add_monowidth_widget(l->data);
// }
// 
// 
// 
// void
// nd_gui_update_view_indicator(void)
// {
//   LND_Trace *trace;
//   ND_Trace *trace_gui;
//   GtkWidget *view_button, *area;
//   double size, fraction;
//   char buf[MAXPATHLEN];
//   off_t offset;
// 
//   D_ENTER;
// 
//   ND_GTK_GET(area, nd_toplevel_window, "view_fixed");
//   ND_GTK_GET(view_button, nd_toplevel_window, "view_fixed_button");
// 
//   if (! (trace = nd_trace_registry_get_current()))
//     {
//       gtk_widget_hide(view_button);
//       D_RETURN;
//     }
// 
//   switch (trace->area.mode)
//     {
//     case LND_TPM_TIME:
//       fraction = libnd_tpm_get_time_fraction(trace->tpm, &trace->tpm->current->start_ts);
//       break;
// 
//     default:
//       offset = libnd_tpm_map_loc_to_offset(trace->tpm, &trace->tpm->current->start);
//       D(("Offset: %lu\n", (long unsigned) offset));
//       fraction = libnd_tpm_get_space_fraction(trace->tpm, offset);
//     }
// 
//   size = libnd_tpm_get_rel_size(trace->tpm);
//   D(("Trace part stats: size = %f, offset = %f\n", size, fraction));
// 
//   /* Position and width of the button -- make sure that the button is
//    * at least 10 pixels wide, and that does fit into the right edge
//    */
//   gtk_widget_set_uposition (view_button, MIN(fraction * area->allocation.width, area->allocation.width - 10), 0);
//   gtk_widget_set_usize (view_button, MAX(size * area->allocation.width, 10),
// 			area->allocation.height / 2);
//   gtk_widget_show(view_button);  
// 
//   /* Also update title column in the list widget: */
//   if (! (trace_gui = nd_trace_get(trace)))
//     D_RETURN;
// 
//   /* If we're at the very beginning, and take all the space,
//    * don't show percentage details.
//    */
//   if (fraction < 0.001 && size > 0.999)
//     {
//       g_snprintf(buf, MAXPATHLEN, _("%s"), list_titles[0]);
//     }
//   else
//     {
//       g_snprintf(buf, MAXPATHLEN, _("%s (%.2f%% of file at %.2f%% offset)"),
// 		 list_titles[0], 100 * size, 100 * fraction);
//     }
// 
//   gtk_clist_set_column_title(GTK_CLIST(trace_gui->list), 0, buf);
//   D_RETURN;
// }
// 
// 
// void
// nd_gui_update_area_indicator(void)
// {
//   LND_Trace *trace;
//   GtkWidget *area_button, *area;
//   double size, start;
// 
//   D_ENTER;
// 
//   ND_GTK_GET(area, nd_toplevel_window, "view_fixed");
//   ND_GTK_GET(area_button, nd_toplevel_window, "view_fixed_area_button");
// 
//   if (! (trace = nd_trace_registry_get_current()))
//     {
//       gtk_widget_hide(area_button);
//       D_RETURN;
//     }
// 
//   switch (trace->area.mode)
//     {
//     case LND_TPM_TIME:
//       start = libnd_tpm_get_time_fraction(trace->tpm, &trace->area.area_time_start);
//       size = libnd_tpm_get_time_fraction(trace->tpm, &trace->area.area_time_end) - start;
//       break;
// 
//     default:
//       start = trace->area.area_space_start;
//       size = trace->area.area_space_end - trace->area.area_space_start;
//     }
// 
//   /* Position and width of the button -- make sure that the button is
//    * at least 10 pixels wide, and that does fit into the right edge
//    */
//   gtk_widget_set_uposition (area_button, MIN(start * area->allocation.width, area->allocation.width - 10),
// 			    area->allocation.height / 2);
//   gtk_widget_set_usize (area_button, MAX(size * area->allocation.width, 10),
// 			area->allocation.height / 2);
//   gtk_widget_show(area_button);  
// 
//   nd_gui_update_view_indicator();
// 
//   D_RETURN;
// }
